package tr.edu.ege.seagent.hobnobontology.instance;

import java.util.ArrayList;
import java.util.List;

import tr.edu.ege.seagent.hobnobontology.schema.HobNobVocabulary;

import com.hp.hpl.jena.query.Dataset;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.rdf.model.ResourceFactory;
import com.hp.hpl.jena.rdf.model.Statement;
import com.hp.hpl.jena.tdb.TDBFactory;

public class HobNobNamedGraph {

	/**
	 * Uses for to connect to the existing store which directory path is
	 * identified to {@link HobNobTDBStore#MODEL_DIRECTORY}.
	 */
	private Dataset dataset;
	private Model istanbulGraphModel;
	private Model izmirGraphModel;
	private Model defaultGraphModel;

	public HobNobNamedGraph() {
		this.defaultGraphModel = new HobNobSampleModelCreator()
				.createModelExceptForSeagent();
		this.izmirGraphModel = new HobNobSampleModelCreator()
				.createSeagentModel();
		this.istanbulGraphModel = new HobNobTDBStore()
				.createIstanbulStatements();
		dataset = TDBFactory.createDataset(HobNobTDBStore.MODEL_DIRECTORY);
	}

	/**
	 * This function provides us to create named graphs which names are
	 * seagentNotification and istanbulNotification. Apart from this TDB-store
	 * includes default graph which context is identified that the statements
	 * which except that seagentNotificitaion statements and
	 * istanbulNotification statements.
	 */
	public void createNamedGraphWithOtherCreationAlgorithm() {
		Model defaultModel = dataset.getDefaultModel();
		defaultModel.add(defaultGraphModel);

		dataset.addNamedModel(HobNobInstanceVocabulary.GRAPH_IZMIR,
				izmirGraphModel);
		dataset.addNamedModel(HobNobInstanceVocabulary.GRAPH_ISTANBUL,
				istanbulGraphModel);

		defaultModel.commit();
		dataset.getNamedModel(HobNobInstanceVocabulary.GRAPH_IZMIR).commit();
		dataset.getNamedModel(HobNobInstanceVocabulary.GRAPH_ISTANBUL).commit();
	}

	/**
	 * This function provides us to create named graphs which names are
	 * seagentNotification and istanbulNotification. Apart from this TDB-store
	 * includes default graph which context is identified that the statements
	 * which except that seagentNotificitaion statements and
	 * istanbulNotification statements.
	 */
	public void createNamedGraphWithUsingDefaultGraph() {
		// gets default model from dataset...
		Model tdbDefaultModel = dataset.getDefaultModel();

		// save seagent notification...
		saveNotificationsInCityToNamedGraph(HobNobInstanceVocabulary.IZMIR_URI,
				HobNobInstanceVocabulary.GRAPH_IZMIR);
		// save istanbul notification...
		saveNotificationsInCityToNamedGraph(
				HobNobInstanceVocabulary.ISTANBUL_URI,
				HobNobInstanceVocabulary.GRAPH_ISTANBUL);

		// commit changes...
		tdbDefaultModel.commit();
		dataset.getNamedModel(HobNobInstanceVocabulary.GRAPH_IZMIR).commit();
		dataset.getNamedModel(HobNobInstanceVocabulary.GRAPH_ISTANBUL).commit();

	}

	/**
	 * This function provide us to find notifications in city and add statements
	 * to the named graph with given finded statements and graph name
	 * 
	 * @param placeURI
	 *            URI of place which uses for find notifications.
	 * @param graphName
	 *            name of graph which also URI.
	 */
	private void saveNotificationsInCityToNamedGraph(String placeURI,
			String graphName) {

		// find statements which relevant seagent notification and location
		// instances...
		List<Statement> notificationStmt = findNotificationStatements(placeURI);
		// add finded statements which relevant to seagentNotification, to the
		// named graph...
		addTriplesToNamedGraph(notificationStmt, graphName);
	}

	/**
	 * This function provide us to find locations related with given placeURI
	 * and notifications related with finded locations. Than finds all
	 * statements that related with this notifications and locations.
	 * 
	 * @param placeURI
	 *            URI of place. It can be
	 *            {@link HobNobInstanceVocabulary#IZMIR_URI} of
	 *            {@link HobNobInstanceVocabulary#ISTANBUL_URI}
	 * @return
	 */
	private List<Statement> findNotificationStatements(String placeURI) {

		List<Statement> notificationAndLocationStmt = new ArrayList<Statement>();
		// finds location resource...
		List<Resource> locations = findLocationsInPlace(placeURI);
		// finds notification resource with given locations list...
		List<Resource> notifications = findNotificationInLocation(locations);

		for (Resource notification : notifications) {
			// add notification statements which related with given placeURI...
			notificationAndLocationStmt.addAll(notification.listProperties()
					.toList());
			// find notification's location object.
			Resource location = notification
					.getPropertyResourceValue(ResourceFactory
							.createProperty(HobNobVocabulary.NOTIFICATION_AT_LOCATION_URI));

			// add location statements which related with given placeURI...
			notificationAndLocationStmt.addAll(location.listProperties()
					.toList());

		}
		// remove this notification and location statements from the default
		// model...
		dataset.getDefaultModel().remove(notificationAndLocationStmt);

		return notificationAndLocationStmt;
	}

	/**
	 * This function provide us to add statements which finded by searching
	 * algorithm, to the named graph.
	 * 
	 * @param notificationModel
	 *            it may be seagent or istanbul notification.
	 * @param notificationStmt
	 *            finded notifications.
	 * @param graphURI
	 *            name of named-Graph.
	 */
	private void addTriplesToNamedGraph(List<Statement> notificationStmt,
			String graphURI) {

		// create default model...
		Model notificationModel = ModelFactory.createDefaultModel();
		// traverse notification statement list...
		for (int i = 0; i < notificationStmt.size(); i++) {
			// add triples to the named graph...
			notificationModel.getGraph()
					.add(notificationStmt.get(i).asTriple());
		}
		// add named graph to the dataset...
		dataset.addNamedModel(graphURI, notificationModel);
	}

	/**
	 * This function takes a placeURI as a parameter and with help this
	 * parameter finds subjects of this placeURI resource.
	 * 
	 * @param placeURI
	 *            URI of object resource.
	 * 
	 * 
	 * @return finded location subjects.
	 */
	private List<Resource> findLocationsInPlace(String placeURI) {

		// gets location subjects from default model in dataset with given
		// placeURI...
		List<Resource> locationResources = dataset
				.getDefaultModel()
				.listSubjectsWithProperty(
						ResourceFactory
								.createProperty(HobNobVocabulary.LOCATION_HAS_DBPEDIA_URI),
						ResourceFactory.createResource(placeURI)).toList();
		return locationResources;
	}

	/**
	 * This function provide us to find notification statements which related
	 * with given location resource.
	 * 
	 * @param location
	 * @return notification resource list
	 */
	private List<Resource> findNotificationInLocation(List<Resource> locations) {

		List<Resource> notificationResources = new ArrayList<Resource>();
		// traverse location subjects and finds notification resources.
		for (Resource location : locations) {
			notificationResources
					.addAll(dataset
							.getDefaultModel()
							.listSubjectsWithProperty(
									ResourceFactory
											.createProperty(HobNobVocabulary.NOTIFICATION_AT_LOCATION_URI),
									location).toList());
		}
		return notificationResources;

	}

}
